/**
 * 
 */
package denaris.core;

import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;

import denaris.core.controller.AbstractController;
import denaris.core.controller.NortheastReflectorControllerFeature;
import denaris.core.controller.SoutheastReflectorControllerFeature;
import denaris.core.entity.AbstractEntity;
import denaris.core.entity.Enemy;
import denaris.core.entity.Player;
import denaris.core.listener.ICollisionListener;
import denaris.midlet.GameScreen;

/**
 * This is the players weapon system. All weapons are particle emitters that are
 * attached to this system.
 * 
 * @author stkl23
 * 
 */
public class PlayerBulletSystem extends BulletSystem {
	private static Sprite collisionTester;

	private BulletEmitter primaryEmitter;

	private ReflectorEmitter reflectorNorthEast;

	private ReflectorEmitter reflectorSouthEast;

	private NinjaEmitter ninja;
	
	private LaserEmitter laser;
	
	private MissileEmitter missileSouthEast;
	
	private MissileEmitter missileNorthEast;

	private AbstractDenarisMap map;

	/**
	 * The primary bullet controller class
	 */
	public class PrimaryBulletController extends AbstractController {
		public static final int BULLET_SPEED = 32;

		public boolean advance() {
			getSprite().move(BULLET_SPEED, 0);
			if (getSprite().getX() > scope[SCOPE_WIDTH]) {
				return false;
			} else {
				return true;
			}
		}
	}

	public PlayerBulletSystem(AbstractDenarisMap map) {
		this.map = map;
		// create the primary weapon
		primaryEmitter = new BulletEmitter(3, 2, 6,	"/denaris/resource/sprite/bullets.png", 7, 6) {
			private Sprite smallCollisionTester = new Sprite(Image.createImage(8, 6));
			
			public AbstractController createController() {
				return new PrimaryBulletController();
			}

			public void emitt(int x, int y) {
				// add some random value
				super.emitt(x + GameScreen.nextPositiveInt(20), y + 1);
			}

			public boolean collidesWith(AbstractParticle particle, AbstractEntity entity) {
				Sprite sprite = particle.getController().getSprite();
				// set the collision tester sprite to the position of the sprite
				collisionTester.setPosition(sprite.getX(), sprite.getY());
				if (collisionTester.collidesWith(entity.getController().getSprite(), false)) {
					return true;
				}
				return false;
			}

			public boolean collidesWith(AbstractParticle particle, TiledMap map) {
				Sprite sprite = particle.getController().getSprite();
				// we must test the particle against the map for every possible position that the particle can have visited
				int xa = sprite.getX();
				int ya = sprite.getY();
				int steps = PrimaryBulletController.BULLET_SPEED / smallCollisionTester.getWidth();
				for (int i=0; i<steps; i++) {
					smallCollisionTester.setPosition(xa, ya);
					if (smallCollisionTester.collidesWith(map.getLayer(), false)) {
						sprite.setPosition(xa, ya);
						return true;
					}
					xa += smallCollisionTester.getWidth();
				}
				
				return false;
			}
		};

		// create the collision dummy
		collisionTester = new Sprite(Image.createImage(
				PrimaryBulletController.BULLET_SPEED, 6));
		
		// create a collision listener that is shared by all emitters but the
		// reflector weapon and the missile weapon
		CollisionAdapter defaultCollisionAdapter = new CollisionAdapter() {
			public void onCollision(AbstractParticle source, AbstractEntity opponent) {
				// a bullet just hit an opponent
				source.setActive(false);
				score(opponent.getScore());
				if (opponent instanceof Enemy) {
					// enemies assign a special controller when they explode
					((Enemy) opponent).explode();
				} else {
					opponent.explode(0, 0);
					
				}
			}

			public void onCollision(AbstractParticle source, AbstractDenarisMap map) {
				source.setActive(false);
				Sprite sprite = source.getController().getSprite();
//				map.addSmallExplosion(sprite.getX(), sprite.getY());
				map.addCollisionParticles(sprite.getX(), sprite.getY());
			}
		};
		
		CollisionAdapter missileCollisionAdapter = new CollisionAdapter() {
			public void onCollision(AbstractParticle source, AbstractEntity opponent) {
				// a bullet just hit an opponent
				source.setActive(false);
				score(opponent.getScore());
				if (opponent instanceof Enemy) {
					// enemies assign a special controller when they explode
					((Enemy) opponent).explode();
				} else {
					opponent.explode(0, 0);
					
				}
				Sprite sprite = source.getController().getSprite();
				// destory the missile
				getPlayer().getParentMap().addSmallExplosion(sprite.getX(), sprite.getY());
			}

			public void onCollision(AbstractParticle source, AbstractDenarisMap map) {
				source.setActive(false);
				Sprite sprite = source.getController().getSprite();
				map.addSmallExplosion(sprite.getX(), sprite.getY());
			}
		};

		// set the collision listener
		primaryEmitter.setCollisionListener(defaultCollisionAdapter);
		// start with the first bullet
		primaryEmitter.setBulletFrame(0);
		// add the emitter to the emitter list
		addEmitter(primaryEmitter);

		// the difference between this collision listener and the one of the
		// primary bullet emitter is that this one doesn't deactivate the bullet
		// once it collided with something
		ICollisionListener indestructibleCollisionListener = new CollisionAdapter() {
			public void onCollision(AbstractParticle source, AbstractEntity opponent) {
				score(opponent.getScore());
				if (opponent instanceof Enemy) {
					// enemies assign a special controller when they explode
					((Enemy) opponent).explode();
				} else {
					opponent.explode(0, 0);
				}
			}
			
			public void onCollision(AbstractParticle source, AbstractDenarisMap map) {
				source.setActive(false);
				Sprite sprite = source.getController().getSprite();
				map.addCollisionParticles(sprite.getX(), sprite.getY());
			}
			
		};

		// create the reflector weapon
		reflectorNorthEast = new ReflectorEmitter(new NortheastReflectorControllerFeature());
		reflectorNorthEast.setCollisionListener(indestructibleCollisionListener);
		reflectorSouthEast = new ReflectorEmitter(new SoutheastReflectorControllerFeature());
		reflectorSouthEast.setCollisionListener(indestructibleCollisionListener);

		addEmitter(reflectorNorthEast);
		addEmitter(reflectorSouthEast);

		ninja = new NinjaEmitter(3, 32, 0, "/denaris/resource/sprite/ninja.png", 8, 8);
		ninja.setCollisionListener(defaultCollisionAdapter);
		addEmitter(ninja);
		
		laser = new LaserEmitter(2, 40, 0, "/denaris/resource/sprite/laser.png", 38, 7);
		laser.setCollisionListener(indestructibleCollisionListener);
		addEmitter(laser);
		
		missileSouthEast = new MissileEmitter(1, MissileEmitter.MISSILE_SPEED, MissileEmitter.MISSILE_SPEED, map);
		missileSouthEast.setCollisionListener(missileCollisionAdapter);
		missileSouthEast.setActive(false);
		addEmitter(missileSouthEast);

		missileNorthEast = new MissileEmitter(1, MissileEmitter.MISSILE_SPEED, -MissileEmitter.MISSILE_SPEED, map);
		missileNorthEast.setCollisionListener(missileCollisionAdapter);
		missileNorthEast.setActive(false);
		addEmitter(missileNorthEast);

		// deactivate all secondary weapons - they are activated when the satellites are collected
		deactivateSecondaryWeapons();
	}

	public void checkCollision(Vector entities) {
		Enumeration e = getEmitters().elements();
		while (e.hasMoreElements()) {
			AbstractParticleEmitter emitter = (AbstractParticleEmitter) e
					.nextElement();
			if (emitter instanceof BulletEmitter) {
				BulletEmitter bulletEmitter = (BulletEmitter) emitter;
				bulletEmitter.checkCollision(entities);
				bulletEmitter.checkCollision((TiledMap)map);
			} else if (emitter instanceof ReflectorEmitter) {
				ReflectorEmitter reflectorEmitter = (ReflectorEmitter) emitter;
				reflectorEmitter.checkCollision(entities);
				reflectorEmitter.checkCollision((TiledMap)map);
			}
		}
	}

	public BulletEmitter getPrimaryEmitter() {
		return primaryEmitter;
	}

	public void activateReflector() {
		// activate the reflectors
		reflectorNorthEast.setActive(true);
		reflectorSouthEast.setActive(true);
		// deactivate the ninja
		ninja.setActive(false);
		laser.setActive(false);
		primaryEmitter.setActive(true);
	}

	public void activateNinja() {
		// activate the ninja weapon
		ninja.setActive(true);
		// deactivate the reflectors
		reflectorNorthEast.setActive(false);
		reflectorSouthEast.setActive(false);
		laser.setActive(false);
		primaryEmitter.setActive(true);
	}
	
	public void deactivateSecondaryWeapons() {
		ninja.setActive(false);
		reflectorNorthEast.setActive(false);
		reflectorSouthEast.setActive(false);
		laser.setActive(false);
	}
	
	public void activateLaser() {
		ninja.setActive(false);
		reflectorNorthEast.setActive(false);
		reflectorSouthEast.setActive(false);
		primaryEmitter.setActive(false);
		laser.setActive(true);		
	}

	public MissileEmitter getMissileNorthEast() {
		return missileNorthEast;
	}

	public MissileEmitter getMissileSouthEast() {
		return missileSouthEast;
	}
	
	private Player getPlayer() {
		AbstractEntity player = map.getPlayerGroup();
		if (player instanceof Player) {
			return (Player) player;
		}else {
			return null;
		}
	}
	
	private void score(int score) {
		Player p = getPlayer();
		if (p != null) {
			p.updateScore(score);
		}
	}
	
	public void reset() {
		super.reset();
		deactivateSecondaryWeapons();
		// activate the primary emitter
		getPrimaryEmitter().setActive(true);
	}
}